package com.codedancer.campus.manager.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.codedancer.campus.common.exception.BusinessException;
import com.codedancer.campus.common.utils.UUIDGenerator;
import com.codedancer.campus.manager.async.RoleAsync;
import com.codedancer.campus.manager.service.IRoleService;
import com.codedancer.campus.manager.service.bo.role.RoleAddOrUpdateBo;
import com.codedancer.campus.manager.service.bo.role.RolePageSearchBo;
import com.codedancer.campus.manager.service.vo.role.RolePageVo;
import com.codedancer.campus.manager.service.vo.role.RoleVo;
import com.codedancer.campus.mapper.MenuMapper;
import com.codedancer.campus.mapper.RoleMapper;
import com.codedancer.campus.mapper.RoleMenuMapper;
import com.codedancer.campus.po.Role;
import com.codedancer.campus.po.RoleMenu;
import com.codedancer.campus.qo.role.RolePageSearchQo;
import java.util.List;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@Slf4j
@Transactional(rollbackFor = Exception.class)
public class RoleServiceImpl implements IRoleService {

    @Autowired
    private RoleMapper roleMapper;
    @Autowired
    private RoleMenuMapper roleMenuMapper;
    @Autowired
    private MenuMapper menuMapper;
    @Autowired
    private RoleAsync roleAsync;

    /**
     * 添加角色
     *
     * @param roleAddOrUpdateBo
     */
    @Override
    public void add(RoleAddOrUpdateBo roleAddOrUpdateBo) {
        if (roleMapper.existsByColumn("name", roleAddOrUpdateBo.getName())) {
            throw new BusinessException("角色名称已存在，请重新填写");
        }
        if (roleMapper.existsByColumn("encode", roleAddOrUpdateBo.getEncode())) {
            throw new BusinessException("角色编码已存在，请重新填写");
        }
        Role role = BeanUtil.copyProperties(roleAddOrUpdateBo, Role.class);
        role.setUuid(UUIDGenerator.getUUID());
        roleMapper.insert(role);
        roleAsync.updateRoleEncodeDataCache();
    }

    /**
     * 分页查询角色
     *
     * @param rolePageSearchBo
     * @return
     */
    @Override
    public IPage<RolePageVo> page(RolePageSearchBo rolePageSearchBo) {
        RolePageSearchQo rolePageSearchQo = BeanUtil.copyProperties(rolePageSearchBo,
            RolePageSearchQo.class);
        IPage<Role> roleIPage = roleMapper.page(
            new Page<Role>(rolePageSearchBo.getPage(), rolePageSearchBo.getSize()),
            rolePageSearchQo);
        List<RolePageVo> rolePageVos;
        IPage<RolePageVo> rolePageVoIPage = new Page<>();
        rolePageVos = roleIPage.getRecords().stream().map(role -> {
            return BeanUtil.copyProperties(role, RolePageVo.class);
        }).collect(Collectors.toList());
        rolePageVoIPage.setRecords(rolePageVos);
        rolePageVoIPage.setTotal(roleIPage.getTotal());
        return rolePageVoIPage;
    }

    /**
     * 修改角色
     *
     * @param roleAddOrUpdateBo
     */
    @Override
    public void update(RoleAddOrUpdateBo roleAddOrUpdateBo) {
        Role role = roleMapper.findById(roleAddOrUpdateBo.getUuid())
            .orElseThrow(() -> new BusinessException("角色不存在"));
        if (!role.getName().equals(roleAddOrUpdateBo.getName())) {
            if (roleMapper.existsByColumn("name", roleAddOrUpdateBo.getName())) {
                throw new BusinessException("角色名称已存在，请重新填写");
            }
            role.setName(roleAddOrUpdateBo.getName());
        }
        if (!role.getEncode().equals(roleAddOrUpdateBo.getEncode())) {
            if (roleMapper.existsByColumn("encode", roleAddOrUpdateBo.getEncode())) {
                throw new BusinessException("角色编码已存在，请重新填写");
            }
            role.setEncode(roleAddOrUpdateBo.getEncode());
        }
        role.setRemark(roleAddOrUpdateBo.getRemark());
        roleMapper.updateById(role);
        roleAsync.updateRoleEncodeDataCache();
    }

    /**
     * 获取全部角色
     *
     * @return
     */
    @Override
    public List<RoleVo> all() {
        List<Role> roles = roleMapper.selectList(null);
        return BeanUtil.copyToList(roles, RoleVo.class);
    }

    /**
     * 分配权限
     *
     * @param menuUuids
     * @param roleUuid
     */
    @Override
    public void assignPermissions(List<String> menuUuids, String roleUuid) {
        // 先删除该角色的菜单
        roleMenuMapper.deleteByColumn("role_uuid", roleUuid);
        for (String menuUuid : menuUuids) {
            if (!menuMapper.existsByUuId(menuUuid)) {
                throw new BusinessException("菜单不存在，菜单uuid：" + menuUuid);
            }
            RoleMenu roleMenu = RoleMenu.builder()
                .uuid(UUIDGenerator.getUUID())
                .roleUuid(roleUuid)
                .menuUuid(menuUuid).build();
            roleMenuMapper.insert(roleMenu);
        }
    }

    /**
     * 获取角色菜单权限
     *
     * @param roleUuid
     * @return
     */
    @Override
    public List<String> listMenuByRoleUuid(String roleUuid) {
        List<RoleMenu> roleMenus = roleMenuMapper.selectListByColumn("role_uuid", roleUuid);
        return roleMenus.stream().map(RoleMenu::getMenuUuid).collect(Collectors.toList());
    }
}
